package com.puzzlebazar.server;

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;

import com.puzzlebazar.client.puzzleinfo.PuzzleInfo;
import com.puzzlebazar.client.puzzleinfo.PuzzleInfo.Status;

public abstract class PuzzleListFilter {

	public enum Type {
		PUZZLE_ONLY,
		TUTORIAL_ONLY
	};
	
	/**
	 * @param type Selects the constraint of filter you can pass null 
	 */
	public abstract void setType(Type type);

	/**
	 * @param authorEmail The author to use for this query, null for none
	 */
	public abstract void setAuthorEmail(String authorEmail);

	/**
	 * @param needModelInDatastore True to ask that the object has a model in the datastore,
	 * 								false to ask that it DOES NOT have a model,
	 * 								don't call this method if you don't care or pass null
	 */
	public abstract void setNeedModelInDatastore(Boolean needModelInDatastore);

	/**
	 * Sets the list of genres to return with this query
	 * 
	 * @param genres The list of genres, null for all genres
	 * @return 
	 */
	public abstract void setGenres(Vector<String> genres);

	/**
	 * @param genre A new genre to add to the list of genres returned with this query
	 * @return 
	 */
	public abstract void addGenre(String genre);

	/**
	 * Sets the list of statuses to return with this query
	 * 
	 * @param statuses The list of statuses, null for all statuses
	 */
	public abstract void setStatuses(Vector<Status> statuses);

	/**
	 * @param status A new status to add to the list of statuses returned with this query
	 */
	public abstract void addStatus(Status status);

	/**
	 * Executes the query and build the list of puzzles
	 * 
	 * @return The list of puzzle info for this query
	 */
	public abstract LinkedList<PuzzleInfo> runQuery();


	/**
	 * Merge one ordered list into an other. The lists must be ordered by: 
	 *     datePublished DESC, dateEdited DESC, dateCreated DESC
	 * 
	 * @param destination The list to merge into
	 * @param source The list to merge
	 */
	protected static void mergeInto(LinkedList<PuzzleInfo> destination, List<PuzzleInfoJdo> source) {
		
		ListIterator<PuzzleInfo> destinationIterator = destination.listIterator();
		ListIterator<PuzzleInfoJdo> sourceIterator = source.listIterator();
	
		while( sourceIterator.hasNext() ) {
			PuzzleInfo sourceElement = new PuzzleInfo();
			sourceIterator.next().to(sourceElement, false);
			PuzzleInfo destinationElement = null;
			while( destinationIterator.hasNext() ) {
				destinationElement = destinationIterator.next();
				int comparison = sourceElement.compareTo(destinationElement);
				if( comparison > 0 )
					destinationIterator.previous();
				if( comparison >= 0 )
					break;
			}
			if( destinationElement == null ||
					!destinationElement.getKey().equals( sourceElement.getKey() ) )
				destinationIterator.add( sourceElement );
		}
		
	}
	

	/**
	 * Merge one ordered list into an other. The lists must be ordered by: 
	 *     datePublished DESC, dateEdited DESC, dateCreated DESC
	 * 
	 * @param destination The list to merge into
	 * @param source The list to merge
	 */
	protected static void mergeInto(LinkedList<PuzzleInfo> destination, LinkedList<PuzzleInfo> source) {
		
		ListIterator<PuzzleInfo> destinationIterator = destination.listIterator();
		ListIterator<PuzzleInfo> sourceIterator = source.listIterator();
	
		while( sourceIterator.hasNext() ) {
			PuzzleInfo sourceElement = sourceIterator.next();
			PuzzleInfo destinationElement = null;
			while( destinationIterator.hasNext() ) {
				destinationElement = destinationIterator.next();
				int comparison = sourceElement.compareTo(destinationElement);
				if( comparison > 0 )
					destinationIterator.previous();
				if( comparison >= 0 )
					break;
			}
			if( destinationElement == null ||
					!destinationElement.getKey().equals( sourceElement.getKey() ) )
				destinationIterator.add( sourceElement );
		}
		
	}			
	
}